package com.quectel.util.kit;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.SerializerFactory;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

/**
 * <pre>
 * kryo序列化工具
 * 需要注意的是对象无需实现Serializable接口
 * </pre>
 *
 * @author caolu
 * @email louis.cao@quectel.com
 */
public class KryoKit {

    /**
     * 线程安全的Kryo
     */
    private static final ThreadLocal<Kryo> KRYO_THREAD_LOCAL = ThreadLocal.withInitial(() -> {
        Kryo kryo = new Kryo();
        // 避免版本变化
        kryo.setRegistrationRequired(false);
        // 检测循环依赖
        kryo.setReferences(true);
        // 开启后字段新增和删除不报错
        kryo.setDefaultSerializer(new SerializerFactory.CompatibleFieldSerializerFactory());
        return kryo;
    });

    /**
     * 序列化
     *
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {

        try (Output output = new Output(128, -1)) {
            Kryo kryo = KRYO_THREAD_LOCAL.get();
            kryo.writeClassAndObject(output, object);
            return output.toBytes();
        } catch (KryoException e) {
            throw new KryoException("Kryo serialization error", e);
        }
    }

    /**
     * 反序列化
     *
     * @param data
     * @return
     */
    public static Object deserialize(byte[] data) {
        try (Input input = new Input(data)) {
            Kryo kryo = KRYO_THREAD_LOCAL.get();
            return kryo.readClassAndObject(input);
        } catch (KryoException e) {
            throw new KryoException("Kryo deserialization error", e);
        }
    }
}
